home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / daemons / init / sysvinit.000 / sysvinit / sysvinit-2.64 / start-stop-daemon.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-23  |  8.8 KB  |  430 lines

  1. /*
  2.  * A rewrite of the original Debian's start-stop-daemon Perl script
  3.  * in C (faster - it is executed many times during system startup).
  4.  *
  5.  * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
  6.  * public domain.
  7.  */
  8.  
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <stdarg.h>
  13. #include <signal.h>
  14. #include <sys/stat.h>
  15. #include <dirent.h>
  16. #include <unistd.h>
  17. #include <getopt.h>
  18. #include <pwd.h>
  19.  
  20. #define VERSION "version 0.3, 1996-06-05"
  21.  
  22. static int testmode = 0;
  23. static int quietmode = 0;
  24. static int exitnodo = 1;
  25. static int start = 0;
  26. static int stop = 0;
  27. static int signal_nr = 15;
  28. static int user_id = -1;
  29. static const char *userspec = NULL;
  30. static const char *cmdname = NULL;
  31. static char *execname = NULL;
  32. static char *startas = NULL;
  33. static const char *pidfile = NULL;
  34. static const char *progname = "";
  35.  
  36. static struct stat exec_stat;
  37.  
  38. struct pid_list {
  39.     struct pid_list *next;
  40.     int pid;
  41. };
  42.  
  43. static struct pid_list *found = NULL;
  44. static struct pid_list *killed = NULL;
  45.  
  46. static void *xmalloc(int size);
  47. static void push(struct pid_list **list, int pid);
  48. static void do_help(void);
  49. static void parse_options(int argc, char * const *argv);
  50. static int pid_is_exec(int pid, const struct stat *esb);
  51. static int pid_is_user(int pid, int uid);
  52. static int pid_is_cmd(int pid, const char *name);
  53. static void check(int pid);
  54. static void do_pidfile(const char *name);
  55. static void do_procfs(void);
  56. static void do_stop(void);
  57.  
  58. #ifdef __GNUC__
  59. static void fatal(const char *format, ...)
  60.     __attribute__((noreturn, format(printf, 1, 2)));
  61. static void badusage(const char *msg)
  62.     __attribute__((noreturn));
  63. #else
  64. static void fatal(const char *format, ...);
  65. static void badusage(const char *msg);
  66. #endif
  67.  
  68. static void
  69. fatal(const char *format, ...)
  70. {
  71.     va_list arglist;
  72.  
  73.     fprintf(stderr, "%s: ", progname);
  74.     va_start(arglist, format);
  75.     vfprintf(stderr, format, arglist);
  76.     va_end(arglist);
  77.     putc('\n', stderr);
  78.     exit(2);
  79. }
  80.  
  81.  
  82. static void *
  83. xmalloc(int size)
  84. {
  85.     void *ptr;
  86.  
  87.     ptr = malloc(size);
  88.     if (ptr)
  89.         return ptr;
  90.     fatal("malloc(%d) failed", size);
  91. }
  92.  
  93.  
  94. static void
  95. push(struct pid_list **list, int pid)
  96. {
  97.     struct pid_list *p;
  98.  
  99.     p = xmalloc(sizeof(*p));
  100.     p->next = *list;
  101.     p->pid = pid;
  102.     *list = p;
  103. }
  104.  
  105.  
  106. static void
  107. do_help(void)
  108. {
  109.     printf("\
  110. start-stop-daemon for Debian Linux - small and fast C version written by\n\
  111. Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, public domain.\n"
  112. VERSION "\n\
  113. \n\
  114. Usage:
  115.     start-stop-daemon -S|--start options ... -- arguments ...\n\
  116.     start-stop-daemon -K|--stop options ...\n\
  117.     start-stop-daemon -H|--help\n\
  118.     start-stop-daemon -V|--version\n\
  119. \n\
  120. Options (at least one of --exec|--pidfile|--user is required):
  121.     -x|--exec <executable>       program to start/check if it is running\n\
  122.     -p|--pidfile <pid-file>      pid file to check\n\
  123.     -u|--user <username>|<uid>   stop this user's processes\n\
  124.     -n|--name <process-name>     stop processes with this name\n\
  125.     -s|--signal <signal>         signal to send (default 15)\n\
  126.     -a|--startas <pathname>      program to start (default <executable>)\n\
  127.     -t|--test                    test mode, don't do anything\n\
  128.     -o|--oknodo                  exit status 0 (not 1) if nothing done\n\
  129.     -q|--quiet  |  -v, --verbose\n\
  130. \n\
  131. Exit status:  0 = done  1 = nothing done (=> 0 if --oknodo)  2 = trouble\n");
  132. }
  133.  
  134.  
  135. static void
  136. badusage(const char *msg)
  137. {
  138.     if (msg && *msg)
  139.         fprintf(stderr, "%s: %s\n", progname, msg);
  140.     fprintf(stderr, "Try `%s --help' for more information.\n", progname);
  141.     exit(2);
  142. }
  143.  
  144.  
  145. static void
  146. parse_options(int argc, char * const *argv)
  147. {
  148.     static struct option longopts[] = {
  149.         { "help",    0, NULL, 'H'},
  150.         { "stop",    0, NULL, 'K'},
  151.         { "start",    0, NULL, 'S'},
  152.         { "version",    0, NULL, 'V'},
  153.         { "startas",    1, NULL, 'a'},
  154.         { "name",    1, NULL, 'n'},
  155.         { "oknodo",    0, NULL, 'o'},
  156.         { "pidfile",    1, NULL, 'p'},
  157.         { "quiet",    0, NULL, 'q'},
  158.         { "signal",    1, NULL, 's'},
  159.         { "test",    0, NULL, 't'},
  160.         { "user",    1, NULL, 'u'},
  161.         { "verbose",    0, NULL, 'v'},
  162.         { "exec",    1, NULL, 'x'},
  163.         { NULL,        0, NULL, 0}
  164.     };
  165.     int c;
  166.  
  167.     for (;;) {
  168.         c = getopt_long(argc, argv, "HKSVa:n:op:qs:tu:vx:",
  169.                 longopts, (int *) 0);
  170.         if (c == -1)
  171.             break;
  172.         switch (c) {
  173.         case 'H':  /* --help */
  174.             do_help();
  175.             exit(0);
  176.         case 'K':  /* --stop */
  177.             stop = 1;
  178.             break;
  179.         case 'S':  /* --start */
  180.             start = 1;
  181.             break;
  182.         case 'V':  /* --version */
  183.             printf("start-stop-daemon " VERSION "\n");
  184.             exit(0);
  185.         case 'a':  /* --startas <pathname> */
  186.             startas = optarg;
  187.             break;
  188.         case 'n':  /* --name <process-name> */
  189.             cmdname = optarg;
  190.             break;
  191.         case 'o':  /* --oknodo */
  192.             exitnodo = 0;
  193.             break;
  194.         case 'p':  /* --pidfile <pid-file> */
  195.             pidfile = optarg;
  196.             break;
  197.         case 'q':  /* --quiet */
  198.             quietmode = 1;
  199.             break;
  200.         case 's':  /* --signal <signal> */
  201.             if (sscanf(optarg, "%d", &signal_nr) != 1)
  202.                 badusage("--signal takes a numeric argument");
  203.             break;
  204.         case 't':  /* --test */
  205.             testmode = 1;
  206.             break;
  207.         case 'u':  /* --user <username>|<uid> */
  208.             userspec = optarg;
  209.             break;
  210.         case 'v':  /* --verbose */
  211.             quietmode = -1;
  212.             break;
  213.         case 'x':  /* --exec <executable> */
  214.             execname = optarg;
  215.             break;
  216.         default:
  217.             badusage("");  /* message printed by getopt */
  218.         }
  219.     }
  220.  
  221.     if (start == stop)
  222.         badusage("need one of --start or --stop");
  223.  
  224.     if (!execname && !pidfile && !userspec)
  225.         badusage("need at least one of --exec, --pidfile or --user");
  226.  
  227.     if (!startas)
  228.         startas = execname;
  229.  
  230.     if (start && !startas)
  231.         badusage("--start needs --exec or --startas");
  232. }
  233.  
  234.  
  235. static int
  236. pid_is_exec(int pid, const struct stat *esb)
  237. {
  238.     struct stat sb;
  239.     char buf[32];
  240.  
  241.     sprintf(buf, "/proc/%d/exe", pid);
  242.     if (stat(buf, &sb) != 0)
  243.         return 0;
  244.     return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
  245. }
  246.  
  247.  
  248. static int
  249. pid_is_user(int pid, int uid)
  250. {
  251.     struct stat sb;
  252.     char buf[32];
  253.  
  254.     sprintf(buf, "/proc/%d", pid);
  255.     if (stat(buf, &sb) != 0)
  256.         return 0;
  257.     return (sb.st_uid == uid);
  258. }
  259.  
  260.  
  261. static int
  262. pid_is_cmd(int pid, const char *name)
  263. {
  264.     char buf[32];
  265.     FILE *f;
  266.     int c;
  267.  
  268.     sprintf(buf, "/proc/%d/stat", pid);
  269.     f = fopen(buf, "r");
  270.     if (!f)
  271.         return 0;
  272.     while ((c = getc(f)) != EOF && c != '(')
  273.         ;
  274.     if (c != '(') {
  275.         fclose(f);
  276.         return 0;
  277.     }
  278.     /* this hopefully handles command names containing ')' */
  279.     while ((c = getc(f)) != EOF && c == *name)
  280.         name++;
  281.     fclose(f);
  282.     return (c == ')' && *name == '\0');
  283. }
  284.  
  285.  
  286. static void
  287. check(int pid)
  288. {
  289.     if (execname && !pid_is_exec(pid, &exec_stat))
  290.         return;
  291.     if (userspec && !pid_is_user(pid, user_id))
  292.         return;
  293.     if (cmdname && !pid_is_cmd(pid, cmdname))
  294.         return;
  295.     push(&found, pid);
  296. }
  297.  
  298.  
  299. static void
  300. do_pidfile(const char *name)
  301. {
  302.     FILE *f;
  303.     int pid;
  304.  
  305.     f = fopen(name, "r");
  306.     if (f) {
  307.         if (fscanf(f, "%d", &pid) == 1)
  308.             check(pid);
  309.         fclose(f);
  310.     }
  311. }
  312.  
  313.  
  314. static void
  315. do_procfs(void)
  316. {
  317.     DIR *procdir;
  318.     struct dirent *entry;
  319.     int foundany, pid;
  320.  
  321.     procdir = opendir("/proc");
  322.     if (!procdir)
  323.         fatal("opendir /proc: %s", strerror(errno));
  324.  
  325.     foundany = 0;
  326.     while ((entry = readdir(procdir)) != NULL) {
  327.         if (sscanf(entry->d_name, "%d", &pid) != 1)
  328.             continue;
  329.         foundany++;
  330.         check(pid);
  331.     }
  332.     closedir(procdir);
  333.     if (!foundany)
  334.         fatal("nothing in /proc - not mounted?");
  335. }
  336.  
  337.  
  338. static void
  339. do_stop(void)
  340. {
  341.     char what[1024];
  342.     struct pid_list *p;
  343.  
  344.     if (cmdname)
  345.         strcpy(what, cmdname);
  346.     else if (execname)
  347.         strcpy(what, execname);
  348.     else if (pidfile)
  349.         sprintf(what, "process in pidfile `%s'", pidfile);
  350.     else if (userspec)
  351.         sprintf(what, "process(es) owned by `%s'", userspec);
  352.     else
  353.         fatal("internal error, please report");
  354.  
  355.     if (!found) {
  356.         if (quietmode <= 0)
  357.             printf("no %s found; none killed.\n", what);
  358.         exit(exitnodo);
  359.     }
  360.     for (p = found; p; p = p->next) {
  361.         if (testmode)
  362.             printf("would send signal %d to %d.\n",
  363.                    signal_nr, p->pid);
  364.         else if (kill(p->pid, signal_nr) == 0)
  365.             push(&killed, p->pid);
  366.         else
  367.             printf("%s: warning: failed to kill %d: %s\n",
  368.                    progname, p->pid, strerror(errno));
  369.     }
  370.     if (quietmode < 0 && killed) {
  371.         printf("stopped %s (pid", what);
  372.         for (p = killed; p; p = p->next)
  373.             printf(" %d", p->pid);
  374.         printf(").\n");
  375.     }
  376. }
  377.  
  378.  
  379. int
  380. main(int argc, char **argv)
  381. {
  382.     progname = argv[0];
  383.  
  384.     parse_options(argc, argv);
  385.     argc -= optind;
  386.     argv += optind;
  387.  
  388.     if (execname && stat(execname, &exec_stat))
  389.         fatal("stat %s: %s", execname, strerror(errno));
  390.  
  391.     if (userspec && sscanf(userspec, "%d", &user_id) != 1) {
  392.         struct passwd *pw;
  393.  
  394.         pw = getpwnam(userspec);
  395.         if (!pw)
  396.             fatal("user `%s' not found\n", userspec);
  397.  
  398.         user_id = pw->pw_uid;
  399.     }
  400.  
  401.     if (pidfile)
  402.         do_pidfile(pidfile);
  403.     else
  404.         do_procfs();
  405.  
  406.     if (stop) {
  407.         do_stop();
  408.         exit(0);
  409.     }
  410.  
  411.     if (found) {
  412.         if (quietmode <= 0)
  413.             printf("%s already running.\n", execname);
  414.         exit(exitnodo);
  415.     }
  416.     if (testmode) {
  417.         printf("would start %s ", startas);
  418.         while (argc-- > 0)
  419.             printf("%s ", *argv++);
  420.         printf(".\n");
  421.         exit(0);
  422.     }
  423.     if (quietmode < 0)
  424.         printf("starting %s ...\n", startas);
  425.     *--argv = startas;
  426.     execv(startas, argv);
  427.     fatal("unable to start %s: %s", startas, strerror(errno));
  428. }
  429.  
  430.